﻿using System;
using System.Collections.Generic;

namespace JeanFish
{
    /// <summary>
    /// 表示扩展的数组类型，该类型表示源数组的子数组，同时维持对源数组元素的引用。
    /// </summary>
    /// <typeparam name="T">表示数组元素类型</typeparam>
    public class ExtendedArray<T>:IEnumerable<T>
    {
        T[] source;
        int startIndex;
        int length;
        /// <summary>
        /// 检查给定的索引位置是否超出数组索引范围。
        /// </summary>
        /// <param name="index"></param>
        private void CheckIndex(int index)
        {
            if (index < 0 || index >= length) throw new IndexOutOfRangeException();
        }
        /// <summary>
        /// 检查给定的长度是否超出数组长度。
        /// </summary>
        /// <param name="length"></param>
        private void CheckLength(int length)
        {
            if (length > this.length) throw new IndexOutOfRangeException();
        }
        /// <summary>
        /// 初始化扩展数组。
        /// </summary>
        /// <param name="source">源数组</param>
        /// <param name="startIndex">源数组中的开始索引</param>
        /// <param name="length">扩展子数组的长度</param>
        public ExtendedArray(T[] source, int startIndex, int length)
        {
            this.source = source;
            if (startIndex < 0 || startIndex >= this.source.Length||startIndex+length>this.source.Length) throw new IndexOutOfRangeException();
            this.startIndex = startIndex;
            this.length = length;
        }
        /// <summary>
        /// 从扩展数组初始化扩展数组。
        /// </summary>
        /// <param name="source">源扩展数组</param>
        /// <param name="startIndex">源扩展数组中的开始索引</param>
        /// <param name="length">扩展子数组的长度</param>
        public ExtendedArray(ExtendedArray<T> source, int startIndex, int length)
        {
            this.source = source.source;
            if (startIndex < 0 || startIndex >= source.Length || startIndex + length > source.Length) throw new IndexOutOfRangeException();
            this.startIndex = source.startIndex+startIndex;
            this.length = length;
        }
        /// <summary>
        /// 获取索引对应的数组元素。
        /// </summary>
        /// <param name="index">元素索引位置</param>
        /// <returns>该索引处的元素</returns>
        public T this[int index]
        {
            get
            {
                CheckIndex(index);
                return this.source[startIndex + index];
            }
            set
            {
                CheckIndex(index);
                this.source[startIndex + index] = value;
            }
        }
        /// <summary>
        /// 枚举数组中的元素。
        /// </summary>
        /// <returns>数组元素</returns>
        public IEnumerator<T> GetEnumerator()
        {
            for (int i = startIndex; i < startIndex + length; i++)
            {
                yield return this.source[i];
            }
        }
        /// <summary>
        /// 获取实现System.Collections.IEnumerator接口的迭代器。
        /// </summary>
        /// <returns></returns>
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }
        /// <summary>
        /// 从源数组指定索引复制元素。
        /// </summary>
        /// <param name="source">源数组</param>
        /// <param name="sourceIndex">源数组中的开始索引</param>
        /// <param name="destinationIndex">目标数组中的位置</param>
        /// <param name="length">复制元素的长度</param>
        public void Copy(T[] source, int sourceIndex, int destinationIndex, int length)
        {

            for (int i = 0; i <  length; i++)
            {
                this[destinationIndex + i] = source[sourceIndex + i];
            }
        }
        /// <summary>
        /// 获得扩展数组的长度。
        /// </summary>
        public int Length
        {
            get { return length; }
        }
    }
}